今天開始進入到 Behavioral design patterns,這一類的模式著重於物件之間的溝通與責任分配,就讓我們接下去一起看看吧
當有一個需要處理的需求(或請求)進入系統的時候,這個系統中負責的物件會串成一個鏈,然後讓這個需求依序被處理。在這個過程當中,每一個物件會
假設有一間公司,準備發起一個新的 VIP 會員回饋方案,不過會員本身的點數和經驗需要到一個標準值才能參與。
如果我們的 Member
類別像是下面這樣
class Member {
points: number;
experience: number;
constructor(points: number, experience: number){
this.points = points
this.experience = experience
}
}
const memberA = new Member(1500, 2000)
接下來,我們就可以很簡單寫一個函式來進行判斷。譬如我們希望找到點數大於 1000、經驗值大於 1500 的會員來參與 VIP 會員回饋方案,實作如下:
const handler = (member: Member): boolean => {
const { points, experience } = member
return points > 1000 && experience > 1500
}
但如果未來我們有不同的回饋方案有不同的標準值、又或者說需要加入更多的判斷條件,那麼我們就需要建立更多的 handler 函式,或者是不斷的修改原有的 handler 函式。
如果我們可以用組合的方式,將不同的判斷函式組合成我們需要的函式,可以隨意調整,隨插隨用,是不是就會很方便呢?
接下來讓來看看責任鏈模式可以怎麼處理這個問題
首先,我們建立 Handler
介面,和一個抽象類別。這裡我們定義 handler 當中需要有兩個方法,一個是處理需求的 handle
方法,另一個是記錄下一個 handler 的位置
interface Handler {
handle(member: Member): boolean
next(handler: Handler): Handler
}
abstract class AbstractHandler implements Handler {
protected nextHandler: Handler
next(handler: Handler): Handler {
this.nextHandler = handler
return handler
}
handle(member: Member): boolean {
return false
}
}
接著,我們就可以分別建立處理 points 和處理 experience 的 handler
class PointsHandler extends AbstractHandler {
private limit: number;
constructor(limit: number){
super()
this.limit = limit
}
handle(member: Member): boolean {
if (member.points > this.limit) {
return this.nextHandler
? this.nextHandler.handle(member) && true
: true;
}
return false;
}
}
class ExperienceHandler extends AbstractHandler {
private limit: number;
constructor(limit: number){
super()
this.limit = limit
}
handle(member: Member): boolean {
if (member.experience > this.limit) {
return this.nextHandler
? this.nextHandler.handle(member) && true
: true;
}
return false;
}
}
這裡我們做了幾件事情
handle
方法當中,我們會進行條件判斷,如果不通過,就會直接回傳 false;如果通過,就會看之後的 handler 是否通過,來決定最後的回傳值接下來,我們就可以分別建立 pointsHandler 和 experienceHandler
const pointsHandler = new PointsHandler(1000)
const experienceHandler = new ExperienceHandler(1500)
然後,記得把他們給串連一起
pointsHandler.next(experienceHandler)
最後,我們就可以用來判斷不同 member 的狀況
const memberA = new Member(1500, 2000)
const memberB = new Member(1250, 1250)
const memberC = new Member(750, 750)
pointsHandler.handle(memberA) // true
pointsHandler.handle(memberB) // false,因為 experience 不夠
pointsHandler.handle(memberC) // false,因為 points 和 experience 不夠
所以未來如果我們想要調整判斷的條件限制(譬如降低 points 條件至 500),那麼只要透過 PointsHandler
和 ExperienceHandler
類別建立新的實例即可。
如果我們想要調整判斷的方式(譬如移除 points,新增 level),那麼我們就可以依賴 AbstractHandler
實作另外一個新的 handler,然後用 next
方法把需要的方式給組合在一起
責任鏈模式提供了很高的擴充彈性,讓我們能夠依序處理需求或請求,同時不需要去修改既有的物件或函式。而缺點就是,不一定所有的請求都會被完全處理到。